package org.jflame.web.spring;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import org.jflame.commons.json.JsonHelper;
import org.jflame.commons.model.CallResult;
import org.jflame.commons.model.ResultEnum;
import org.jflame.context.spring.SpringContextHolder;
import org.jflame.web.WebUtils;
import org.springframework.core.Ordered;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.io.IOException;

/**
 * 统一异常处理类,同时支持普通请求和json请求.
 *
 * @author zyc
 */
public class MyExceptionResolver extends SimpleMappingExceptionResolver {

    private GlobalExceptionHandler restExceptionHandler = null;

    public MyExceptionResolver() {
        this(false);
    }

    public MyExceptionResolver(boolean enableLocale) {
        restExceptionHandler = new GlobalExceptionHandler(enableLocale);
    }

    String build(ResultEnum re, String msgCode) {
        return JsonHelper
                .toJson(new CallResult<>(re.getStatus(), SpringContextHolder.getMessage(msgCode, re.getMessage())));
    }

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                                              Exception ex) {
        if (SpringWebUtils.isJsonResult(request, handler)) {
            try {
                return doResolveExceptionForRest(ex, request, response);
            } catch (IOException e) {
                logger.error("异常处理时出错", e);
                return null;
            }
        } else {
            return super.doResolveException(request, response, handler, ex);
        }
    }

    protected ModelAndView doResolveExceptionForRest(Exception ex, HttpServletRequest request,
                                                     HttpServletResponse response) throws IOException {
        if (ex instanceof BindException validEx) {
            WebUtils.outJson(response, restExceptionHandler.handleBindEx(validEx, request));
            return null;
        } else if (ex instanceof ConstraintViolationException validEx) {
            WebUtils.outJson(response, restExceptionHandler.handleConstraintViolationEx(validEx, request));
            return null;
        } else if (ex instanceof ServletRequestBindingException || ex instanceof ValidationException
                || ex instanceof HttpMessageNotReadableException) {
            WebUtils.outJson(response, restExceptionHandler.handleParamEx(ex, request));
            return null;
        } else if (ex instanceof HttpRequestMethodNotSupportedException e) {
            WebUtils.outJson(response, restExceptionHandler.handleReqMethodEx(e, request));
            return null;
        } else {
            CallResult<?> result = restExceptionHandler.handle(ex, request);
            WebUtils.outJson(response, result);
            return null;
        }
    }

    /**
     * 设置异常处理优先级高于DefaultHandlerExceptionResolver
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

}
